CS 5010: Problem Set 10

Out: Monday, November 14, 2016

Due: Monday, November 28, 2016 at 600pm local time.


The goal of this problem set is to give you practice with stateful classes, and pulling and pushing information. It is also intended to give you practice with reusing code from previous problem sets.

Please restrict yourself to the language features discussed in class. You may use state. You may not use class inheritance, but you may use interface inheritance.

Otherwise, the deliverables and instructions for this problem set are the same as for Problem Set 09. As always, you must follow the design recipe, in this case the OO Design Recipe and deliverables as spelled out in Lesson 9.5 and in deliverables.html. Be sure to sync your work and fill out a Work Session Report at the end of every work session. Use the Work Session Report for PS 10.

As with ps09, you may submit your solution in multiple files. See details below.


  1. Your boss at the toy factory has been taking PDP, and he has been persuaded to buy a "framework" from WidgetWorks International. The salesman told him that the WidgetWorks framework eliminates the need for your developers to deal with big-bang. You, of course, know that's not so hard, but your boss, still hungover from his party, is pretty gullible. The salesman explains that with WidgetWorks, call you do is create a WidgetWorks Container(TM), load it up with your widgets and swidgets, and send it a 'run' message. You can even add additional widgets and swidgets while it's running. Your boss is convinced, and tells you to reimplement your Metatoy using the WidgetWorks framework. The framework is delivered as a file called WidgetWorks.rkt that provides three interfaces and one function, as follows:
    ;;; Function:
    
    ;; container-init : NonNegInt NonNegInt -> Container
    ;; GIVEN: the width and height of a canvas
    ;; RETURNS: a Container, initially empty, but which, when run, will
    ;; create a canvas of the given width and height and which will send events
    ;; to the Widgets and SWidgets that are added to it.
    
    ;;; Interfaces:
    
    ;; A Container is an object of any class that implements Container<%>
    
    (define Container<%>
      (interface ()
    
       ; Widget -> Void
       ; GIVEN: A widget
       ; EFFECT: adds the given widget to this container
       add-widget
    
       ; SWidget -> Void
       ; GIVEN: A stateful widget
       ; EFFECT: adds the given swidget to this container
       add-stateful-widget
    
       ; PosReal -> Void
       ; GIVEN: a framerate, in secs/tick
       ; EFFECT: runs the widgets and stateful widgets in this framework
       ; at the given framerate.
       run
    
        ))
    
    ;; A Widget is an object of any class that implements Widget<%>
    
    (define Widget<%>
      (interface ()
    
        ; -> Widget
        ; GIVEN: no arguments
        ; RETURNS: the state of this object that should follow at time t+1.
        after-tick          
    
        ; Integer Integer -> Widget
        ; GIVEN: a location
        ; RETURNS: the state of this object that should follow the
        ; specified mouse event at the given location.
        after-button-down
        after-button-up
        after-drag
        after-move
    
        ; KeyEvent -> Widget
        ; GIVEN: a key event and a time
        ; RETURNS: the state of this object that should follow the
        ; given key event
        after-key-event     
    
        ; Scene -> Scene
        ; GIVEN: a scene
        ; RETURNS: a scene like the given one, but with this object
        ; painted on it.
        add-to-scene
        ))
    
    ;; An SWidget is an object of any class that implements the SWidget<%>
    ;; interface.
    
    ;; A SWidget is like a Widget, but it is stable (stateful).
    
    (define SWidget<%>
      (interface ()
    
        ; -> Void
        ; GIVEN: no arguments
        ; EFFECT: updates this widget to the state it should have
        ; following a tick.
        after-tick          
    
        ; Integer Integer -> Void
        ; GIVEN: a location
        ; EFFECT: updates this widget to the state it should have
        ; following the specified mouse event at the given location.
        after-button-down
        after-button-up
        after-drag
        after-move
    
        ; KeyEvent -> Void
        ; GIVEN: a key event
        ; EFFECT: updates this widget to the state it should have
        ; following the given key event
        after-key-event     
    
        ; Scene -> Scene
        ; GIVEN: a scene
        ; RETURNS: a scene like the given one, but with this object
        ; painted on it.
        add-to-scene
        ))
    

    You are relieved to see that these interfaces are much like the ones you've been working with. Just as the salesman said, you run your widgets and swidgets by creating a Container, adding your widgets and swidgets to it, and then calling the run method on your container. You no longer need to call big-bang yourself.

    Your job is to reimplement the toy from problem set 9, but using the WidgetWorks framework and stateful objects. The specifications and deliverables are exactly the same, except that:

    Turn in your solution as a file named "q1.rkt". Put a copy of WidgetWorks.rkt in the directory with your solution. YOU MAY NOT MODIFY WidgetWorks.rkt IN ANY WAY. WE MAY TEST YOUR SOLUTION WITH OUR OWN IMPLEMENTATION OF Container<%>.

    Hint: in the Week 10 examples, each SBall took the wall as one of its init-fields, and registered itself with the wall during its initialization. The contracts in ps09 rule out an analogous "self-registration" strategy here. So you will have to make the object that creates the toys subscribe each toy to the relevant notification or notifications. Be sure you can explain your registration strategy at codewalk. If this hint is mysterious when you read it, check back when you try to implement make-throbber, etc. ADDED MON 11/21/16: Now that I look at it, I think this hint is more misleading than helpful. So you can safely ignore it. See @1044. Sorry about that. -Prof. Wand

  2. Your boss at the toy factory asks you to produce a new toy inspired by Cubelets, which are square blocks that stick together. The new toy has the following specification:

    1. The toy consists of a canvas that is 600 pixels wide and 500 pixels high.
    2. When the child types "b", a new block pops up on the screen at the location of the last button-down or button-up. The block appears as a 20x20 outline square. The square is initially green. If the child types a "b" before the first button-down or button-up event, then the first block appears in an unspecified but fixed place on the canvas.
    3. A block does not move by itself, but the child can move it around using Smooth Drag. When the block is selected, it appears as red rather than green.
    4. If a block is dragged so that it contacts or overlaps another block, the two blocks become connected. We say that the blocks are teammates.. The property of being a teammate is symmetric and transitive. So if block A is moved to touch block B, then a new team is formed consisting of A and all its teammates, and B and all its teammates.
    5. Two blocks overlap if they intersect at any point. For this purpose, the edges of the block are considered part of the block.
    6. Once two blocks become teammates, they remain teammates forever.
    7. When a block is moved, all its teammates move along with it. If A and B are teammates, and A is dragged in some direction, then B moves the same way.
    8. Only the selected block accumulates teammates. If A is being dragged, and B is a teammate of A, and A's motion causes B to come into contact with C, C does not become a teammate of A and B. In the video below, we call the selected block the "leader." But you can drag a team by selecting any block in the team, so the leader may be different on different drags.

    Here's a demonstration:

    Your solution should be a file named q2.rkt that provides the following two functions and one interface:

    cubelets-init : -> Container
    GIVEN: no arguments
    RETURNS: a Container, initially with no blocks, which when run, will
    run in a 600x500 canvas and process the events in the description above.
    
    make-block : NonNegInt NonNegInt ListOfSBlock -> SBlock
    GIVEN: an x and y position, and a list of blocks
    WHERE: the list of blocks is the list of blocks already on the playground.
    RETURNS: a new block, at the given position, with no teammates
    NOTE: it is up to you as to whether you use the third argument or
    not.  Some implementations may use the third argument; others may not.
    
    You must provide an interface named SBlock<%>.  Your SBlock<%>
    interface should inherit from the SWidget<%> interface and add AT
    LEAST the following methods:
    
    get-team : -> ListOfSBlock
    RETURNS: the teammates of this sblock
    
    add-teammate: SBlock -> Void
    EFFECT: adds the given sblock to this block's team
    
    sblock-x : -> Integer
    sblock-y : -> Integer
    RETURNS: the x or y coordinates of this sblock
    

    You may put more methods in the SBlock<%> interface if you so desire. Remember that a method must appear in the interface if and only if it is called from outside this object.

    There are several places where information must be disseminated in this problem, either by pushing or pulling. Be prepared to identify these and to discuss your design decisions about each of them.

    As in the problem above, you must use WidgetWorks.rkt .

DELIVERING YOUR SOLUTION IN MULTIPLE FILES: As you've no doubt noticed, your programs have become longer, and it is awkward to navigate to a particular definition. So you may split your solution over multiple files if you so desire. Here are some ground rules:

Last modified: Mon Nov 21 08:52:52 Eastern Standard Time 2016